package com.yuanluludev.lib_base.base

import android.text.TextUtils
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.yuanluludev.lib_base.bean.ResultBean
import com.yuanluludev.lib_base.ext.toastFailedMiddle
import com.yuanluludev.lib_base.net.errorMsg
import kotlinx.coroutines.CancellationException
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Job
import kotlinx.coroutines.launch

typealias Block<T> = suspend (CoroutineScope) -> T
typealias Error = suspend (Throwable) -> Unit
typealias Cancel = suspend (Throwable) -> Unit

/**
 * yuanLuu
 * 要求所有 view model 继承此类
 */
open class BaseViewModel : ViewModel() {

    /**
     * 成功的简要回调
     */
    val successResultTip by lazy { MutableLiveData<ResultBean>() }

    /**
     * 失败的简要回调
     */
    val errorResultTip by lazy { MutableLiveData<ResultBean>() }

    /**
     * 显示加载框（指定提示语）
     */
    val showLoadingWithTip by lazy { MutableLiveData<String>() }

    /**
     * 显示默认加载框（提示语是：加载中...）
     */
    val showLoading by lazy { MutableLiveData<Boolean>() }

    /**
     * 隐藏加载框
     */
    val hideLoading by lazy { MutableLiveData<Boolean>() }

    /**
     * 创建并执行协程（默认显示加载框和发生错误时显示错误提示）
     * block 协程中执行
     * error 错误时执行
     * cancel 取消时执行
     * showErrorToast 发生错误时是否弹出错误吐司
     */
    protected fun launch(
        showLoadingWithTip: String = "",
        showLoading: Boolean = true,
        block: Block<Unit>,
        error: Error? = null,
        cancel: Cancel? = null,
        showErrorToast: Boolean = true
    ): Job {
        return viewModelScope.launch {
            try {

                showLoading(showLoadingWithTip, showLoading)
                block.invoke(this)
                hideLoading(showLoadingWithTip, showLoading)

            } catch (t: Throwable) {

                when (t) {
                    is CancellationException -> {
                        cancel?.invoke(t)
                    }
                    else -> {
                        if (showErrorToast) t.errorMsg.toastFailedMiddle()
                        error?.invoke(t)
                    }
                }

                hideLoading(showLoadingWithTip, showLoading)

            }
        }
    }

    /**
     * 取消协程
     * @param job 协程job
     */
    protected fun cancelJob(job: Job?) {
        if (job != null && job.isActive && !job.isCompleted && !job.isCancelled) {
            job.cancel()
        }
    }


    /**
     * 显示加载框
     */
    private fun showLoading(showLoadingWithTip: String, showLoading: Boolean) {
        if (!TextUtils.isEmpty(showLoadingWithTip)) {
            this@BaseViewModel.showLoadingWithTip.value = showLoadingWithTip
        } else {
            if (showLoading) this@BaseViewModel.showLoading.value = true
        }
    }

    /**
     * 隐藏加载框
     */
    private fun hideLoading(showLoadingWithTip: String, showLoading: Boolean) {
        if (!TextUtils.isEmpty(showLoadingWithTip)) {
            this@BaseViewModel.hideLoading.value = true
        } else {
            if (showLoading) this@BaseViewModel.hideLoading.value = true
        }
    }

    /**
     * 发送失败的事件
     */
    protected fun postErrorValue(errorState: Int, errorMessage: String) {
        errorResultTip.value = ResultBean(errorState, errorMessage)
    }

    /**
     * 发送失败的事件
     */
    protected fun postErrorValue(errorState: Int) {
        errorResultTip.value = ResultBean(errorState, "")
    }

    /**
     * 发送成功的事件
     */
    protected fun postSuccessValue(successState: Int, successMessage: String) {
        successResultTip.value = ResultBean(successState, successMessage)
    }

    /**
     * 发送成功的事件
     */
    protected fun postSuccessValue(successState: Int) {
        successResultTip.value = ResultBean(successState, "")
    }

}